import { useEffect, useRef, useState, useCallback } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons';
import { deviceGroupDetailApi, deviceGraphAddApi, deviceGraphEditApi } from '@/api/deviceGraphApi';
import { useRouter } from '@/hooks/useRouter';
import { useViewport, type ViewportState } from '@/hooks/useViewport';

import TopToolbar from './modules/TopToolbar';
import DevicePanel from './modules/DevicePanel';
import X6Canvas from './modules/X6Canvas';
import PropertyPanel from './modules/PropertyPanel';
import ViewportControls from './modules/ViewportControls';

import type { DeviceGraph } from '@/api/deviceGraphApi';
import type { CanvasElement } from './modules/types';

/**
 * 组态图编辑器主组件
 * 提供完整的可视化编辑功能，支持设备拖拽、属性配置、保存与预览等核心功能
 */
const GraphEdit = () => {
  const { id } = useParams();
  const navigate = useNavigate();
  const { navigate: routerNavigate } = useRouter();

  // 状态管理
  const [graphName, setGraphName] = useState('未命名组态图');
  const [elements, setElements] = useState<CanvasElement[]>([]);
  const [edges, setEdges] = useState<any[]>([]); // New state for edges
  const [selectedElement, setSelectedElement] = useState<CanvasElement | any | null>(null);
  const [loading, setLoading] = useState(false);

  // 使用视口管理Hook
  const {
    viewport,
    zoomIn,
    zoomOut,
    reset: resetViewport,
    fitToSize,
    handleWheel,
    startDrag,
    drag,
    endDrag,
    canZoomIn,
    canZoomOut,
  } = useViewport({
    minScale: 0.1,
    maxScale: 3,
    scaleStep: 0.1,
  });

  // 控制左右面板折叠状态
  const [isDevicePanelCollapsed, setIsDevicePanelCollapsed] = useState(false);
  const [isPropertyPanelCollapsed, setIsPropertyPanelCollapsed] = useState(false);
  // 画布尺寸
  const [canvasSize, setCanvasSize] = useState({ width: 1024, height: 980 });

  const [canvasConfig, setCanvasConfig] = useState({
    grid: {
      visible: true,
      type: 'mesh',
      size: 10,
      args: [{ color: '#e5e5e5', thickness: 1 }],
    },
    background: {
      visible: true,
      color: '#ffffff',
      position: 'center',
      repeat: 'no-repeat',
      size: 'cover',
      backgroundImageEnabled: false,
    },
  });

  // X6 Graph实例引用
  const graphRef = useRef<any>(null);

  /**
   * 初始化数据
   */
  useEffect(() => {
    if (id && id !== '-1') {
      loadGraphData(id);
    }
  }, [id]);

  /**
   * 加载组态图数据
   * @param graphId 组态图ID
   */
  const loadGraphData = async (graphId: string) => {
    try {
      setLoading(true);
      const res = await deviceGroupDetailApi({ id: parseInt(graphId, 10) });
      if (res.success && res.data) {
        setGraphName(res.data.name || '未命名组态图');

        // 解析组态图内容
        if (res.data.content) {
          try {
            const parsedContent = JSON.parse(res.data.content);
            if (parsedContent.elements && Array.isArray(parsedContent.elements)) {
              setElements(parsedContent.elements);
            }
            if (parsedContent.edges && Array.isArray(parsedContent.edges)) {
              setEdges(parsedContent.edges);
            }
            if (parsedContent.canvasConfig) {
              setCanvasConfig(parsedContent.canvasConfig);
            }
          } catch (error) {
            console.error('解析组态图内容失败:', error);
            window.$message.error('组态图数据解析失败');
          }
        }
      } else {
        window.$message.error(res.message || '获取组态图失败');
      }
    } catch (error) {
      console.error('获取组态图失败:', error);
      window.$message.error('获取组态图失败，请稍后重试');
    } finally {
      setLoading(false);
    }
  };

  /**
   * 获取清理后的画布内容，用于保存和导出
   * @returns 清理后的画布内容对象
   */
  const getCleanedContent = () => {
    const cleanedElements = elements.map(el => {
      if (el.properties && 'imageUrlFileList' in el.properties) {
        const { imageUrlFileList, ...rest } = el.properties;
        return { ...el, properties: rest };
      }
      return el;
    });
    return {
      elements: cleanedElements,
      edges,
      canvasConfig,
    };
  };

  const handleCanvasConfigChange = (newConfig: any) => {
    setCanvasConfig(prevConfig => ({
      ...prevConfig,
      ...newConfig,
    }));
  };

  /**
   * 处理返回操作
   */
  const handleBack = () => {
    navigate('/device/graph');
  };

  /**
   * 保存组态图
   */
  const handleSave = async () => {
    try {
      setLoading(true);
      const contentToSave = getCleanedContent();

      // 构造保存数据
      const graphData: DeviceGraph = {
        id: id && id !== '-1' ? id : '',
        name: graphName,
        content: JSON.stringify(contentToSave),
        createTime: '',
        updateTime: '',
      };

      let res;
      if (id && id !== '-1') {
        // 编辑模式
        res = await deviceGraphEditApi(graphData);
      } else {
        // 新增模式
        res = await deviceGraphAddApi(graphData);
      }

      if (res.success) {
        window.$message.success('保存成功');
        navigate('/device/graph');
      } else {
        window.$message.error(res.message || '保存失败');
      }
    } catch (error) {
      console.error('保存组态图失败:', error);
      window.$message.error('保存失败，请稍后重试');
    } finally {
      setLoading(false);
    }
  };

  /**
   * 导出组态图
   */
  const handleExport = () => {
    const contentToExport = getCleanedContent();
    const contentString = JSON.stringify(contentToExport, null, 2); // Pretty print JSON
    const filename = graphName || 'graph-config';

    const blob = new Blob([contentString], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `${filename}.json`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  };

  /**
   * 预览组态图
   */
  const handlePreview = () => {
    if (id && id !== '-1') {
      const path = `/device/graph/view/${id}`;
      const isHashRouter = window.location.href.includes('#');
      const url = isHashRouter ? `#${path}` : path;
      window.open(url, '_blank');
    } else {
      window.$message.warning('请先保存组态图再进行预览');
    }
  };

  /**
   * 添加元素
   * @param element 新元素
   */
  const handleAddNode = useCallback((element: CanvasElement) => {
    setElements(prev => [...prev, element]);
  }, []);

  const handleRemoveNode = useCallback((id: string) => {
    setElements(prev => prev.filter(el => el.id !== id));
  }, []);

  const handleAddEdge = useCallback((edge: any) => {
    setEdges(prev => [...prev, edge]);
  }, []);

  const handleRemoveEdge = useCallback((id: string) => {
    setEdges(prev => prev.filter(e => e.id !== id));
  }, []);

  const handleGenericRemove = useCallback(
    (id: string) => {
      // The element to be removed might not be the selected one (e.g. canvas delete key)
      // We need a more robust way to determine if it's a node or edge.
      // For now, we assume the PropertyPanel remove button only removes the selected element.
      if (selectedElement && selectedElement.id === id && 'source' in selectedElement) {
        handleRemoveEdge(id);
      } else {
        handleRemoveNode(id);
      }
    },
    [selectedElement, handleRemoveNode, handleRemoveEdge]
  );

  /**
   * 复制元素
   * @param id 元素ID
   */
  const handleDuplicateElement = useCallback((id: string) => {
    setElements(prev => {
      const originalElement = prev.find(el => el.id === id);
      if (!originalElement) return prev;

      const newElement = JSON.parse(JSON.stringify(originalElement)); // Deep copy

      newElement.id = crypto.randomUUID();
      newElement.properties.name = `${originalElement.properties.name || '未命名'} (副本)`;

      newElement.position.x += 20;
      newElement.position.y += 20;

      const newElements = [...prev, newElement];
      setSelectedElement(newElement);

      return newElements;
    });
  }, []);

  const handleUpdateNode = useCallback((id: string, newValues: Partial<CanvasElement>) => {
    const updateLogic = (element: CanvasElement): CanvasElement => {
      const newElement = JSON.parse(JSON.stringify(element));
      const { position, size, angle, zIndex, properties, ...otherProps } = newValues;
      if (position) newElement.position = { ...newElement.position, ...position };
      if (size) newElement.size = { ...newElement.size, ...size };
      if (angle !== undefined) newElement.angle = angle;
      if (zIndex !== undefined) newElement.zIndex = zIndex;

      // 处理properties，避免嵌套properties
      if (properties) {
        newElement.properties = { ...newElement.properties, ...properties };
      } else {
        // 将其他属性直接添加到properties中，避免重复嵌套
        newElement.properties = { ...newElement.properties, ...otherProps };
      }
      return newElement;
    };
    setElements((prev: CanvasElement[]) => prev.map(el => (el.id === id ? updateLogic(el) : el)));
    setSelectedElement((prev: CanvasElement | any | null) =>
      prev && prev.id === id ? updateLogic(prev as CanvasElement) : prev
    );
  }, []);

  const handleUpdateEdge = useCallback((id: string, newValues: any) => {
    const updateLogic = (edge: any) => {
      // Create a new top-level object
      const newEdge = { ...edge };

      // Only update position-related properties if they are explicitly provided and different
      // This prevents style updates from resetting positions
      if (newValues.source && JSON.stringify(newValues.source) !== JSON.stringify(edge.source)) {
        newEdge.source = newValues.source;
      }

      if (newValues.target && JSON.stringify(newValues.target) !== JSON.stringify(edge.target)) {
        newEdge.target = newValues.target;
      }

      if (
        newValues.vertices &&
        JSON.stringify(newValues.vertices) !== JSON.stringify(edge.vertices)
      ) {
        newEdge.vertices = newValues.vertices;
      }

      // Handle attrs update with deep merge
      if (newValues.attrs) {
        newEdge.attrs = {
          ...newEdge.attrs,
          line: {
            ...(newEdge.attrs?.line || {}),
            ...newValues.attrs.line,
            // Handle markers properly - if explicitly passed, use them; otherwise keep existing
            ...(newValues.attrs.line?.targetMarker !== undefined && {
              targetMarker: newValues.attrs.line.targetMarker,
            }),
            ...(newValues.attrs.line?.sourceMarker !== undefined && {
              sourceMarker: newValues.attrs.line.sourceMarker,
            }),
          },
        };
      }

      // Handle router update
      if (newValues.router) {
        newEdge.router = {
          name: newValues.router.name || newEdge.router?.name || 'er',
          args: newValues.router.args || newEdge.router?.args || { direction: 'H' },
        };
      }

      // Handle connector update
      if (newValues.connector) {
        newEdge.connector = {
          name: newValues.connector.name || newEdge.connector?.name || 'rounded',
          args: newValues.connector.args || {},
        };
      }

      return newEdge;
    };

    setEdges((prev: any[]) => prev.map(e => (e.id === id ? updateLogic(e) : e)));
    setSelectedElement((prev: CanvasElement | any | null) =>
      prev && prev.id === id ? updateLogic(prev) : prev
    );
  }, []);

  const handleUpdateElement = useCallback(
    (id: string, newValues: any) => {
      if (selectedElement && 'source' in selectedElement) {
        handleUpdateEdge(id, newValues);
      } else {
        handleUpdateNode(id, newValues as Partial<CanvasElement>);
      }
    },
    [selectedElement, handleUpdateNode, handleUpdateEdge]
  );

  // 当选中元素被从列表中删除时，自动取消选中
  useEffect(() => {
    if (!selectedElement) return;
    const isNode = 'position' in selectedElement;
    const elementExists = isNode
      ? elements.some(el => el.id === selectedElement.id)
      : edges.some(e => e.id === selectedElement.id);

    if (!elementExists) {
      setSelectedElement(null);
    }
  }, [elements, edges]);

  /**
   * 适应画布大小
   */
  const handleFitToCanvas = useCallback(() => {
    const containerElement = document.getElementById('x6-canvas-container');
    if (!containerElement) return;

    const containerRect = containerElement.getBoundingClientRect();
    fitToSize(
      containerRect.width,
      containerRect.height,
      canvasSize.width,
      canvasSize.height,
      40 // 边距
    );
  }, [fitToSize, canvasSize]);

  /**
   * 处理容器滚轮事件
   */
  const handleContainerWheel = useCallback(
    (e: React.WheelEvent) => {
      const containerElement = e.currentTarget;
      const rect = containerElement.getBoundingClientRect();
      handleWheel(e.nativeEvent, rect);
    },
    [handleWheel]
  );

  /**
   * 处理鼠标拖拽 - 用于平移画布
   */
  const handleMouseDown = useCallback(
    (e: React.MouseEvent) => {
      // 只有在空白区域且按住空格键或中键时才开始拖拽
      if (e.button === 1 || (e.button === 0 && e.target === e.currentTarget)) {
        e.preventDefault();
        startDrag(e.clientX, e.clientY);
      }
    },
    [startDrag]
  );

  const handleMouseMove = useCallback(
    (e: React.MouseEvent) => {
      drag(e.clientX, e.clientY);
    },
    [drag]
  );

  const handleMouseUp = useCallback(() => {
    endDrag();
  }, [endDrag]);

  // 添加全局鼠标事件监听
  useEffect(() => {
    const handleGlobalMouseMove = (e: MouseEvent) => {
      drag(e.clientX, e.clientY);
    };

    const handleGlobalMouseUp = () => {
      endDrag();
    };

    document.addEventListener('mousemove', handleGlobalMouseMove);
    document.addEventListener('mouseup', handleGlobalMouseUp);

    return () => {
      document.removeEventListener('mousemove', handleGlobalMouseMove);
      document.removeEventListener('mouseup', handleGlobalMouseUp);
    };
  }, [drag, endDrag]);

  /**
   * 清空画布
   */
  const handleClearCanvas = () => {
    // 清空所有元素和边
    setElements([]);
    setEdges([]);
    // 取消选中状态
    setSelectedElement(null);
    // 提示用户
    window.$message.success('画布已清空');
  };

  // 切换设备库折叠状态
  const toggleDevicePanel = () => {
    setIsDevicePanelCollapsed(prev => !prev);
  };

  // 切换属性面板折叠状态
  const togglePropertyPanel = () => {
    setIsPropertyPanelCollapsed(prev => !prev);
  };

  // 阻断箭头滚动
  const handleScroll = () => {
    const scrollBox = document.getElementById('x6-canvas-over');
    if (scrollBox) {
      scrollBox.addEventListener('keydown', event => {
        // 阻止所有方向键的默认滚动行为，让X6Canvas处理键盘移动
        if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
          event.preventDefault(); // 禁止滚动
        }
      });
    }
  };

  useEffect(() => {
    handleScroll();
  }, []);

  return (
    <div className="graph-edit-container flex flex-col h-full bg-white">
      {/* 顶部工具栏 */}
      <div className="shadow-md z-10 w-full overflow-auto">
        <TopToolbar
          graphName={graphName}
          onNameChange={setGraphName}
          onBack={handleBack}
          onSave={handleSave}
          onPreview={handlePreview}
          onExport={handleExport}
          onZoomIn={zoomIn}
          onZoomOut={zoomOut}
          onResetZoom={resetViewport}
          onClearCanvas={handleClearCanvas}
          scale={viewport.scale}
          canvasSize={canvasSize}
          onCanvasSizeChange={setCanvasSize}
        />
      </div>

      {/* 主体内容区域 */}
      <div className="flex w-full flex-1 overflow-hidden">
        {/* 左侧设备面板 */}
        <div
          className={`flex flex-col h-full border-r border-gray-200 bg-white transition-all duration-300 ease-in-out shadow-md z-10 ${
            isDevicePanelCollapsed ? 'w-14' : 'w-64'
          }`}
        >
          <div
            className={`flex items-center p-2 border-b cursor-pointer bg-gray-50 ${
              isDevicePanelCollapsed ? 'justify-center' : 'justify-between'
            }`}
            onClick={toggleDevicePanel}
          >
            {!isDevicePanelCollapsed && <span className="text-sm font-bold">设备库</span>}
            <span aria-label="折叠/展开设备库">
              {isDevicePanelCollapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
            </span>
          </div>
          {!isDevicePanelCollapsed && (
            <div className="flex-1 overflow-y-auto">
              <DevicePanel
                onDragStart={deviceType => {
                  // 在拖拽开始时，将设备类型存储在dataTransfer中
                  // X6Canvas会监听drop事件并获取这个设备类型
                }}
                onDragEnd={() => {
                  // 拖拽结束时的处理
                }}
              />
            </div>
          )}
        </div>
        <div className="flex-1 relative overflow-hidden">
          {/* 中间画布区域 */}
          <div
            id="x6-canvas-container"
            className="w-full h-full  bg-gray-100 overflow-auto select-none cursor-grab active:cursor-grabbing"
            onWheel={handleContainerWheel}
            onMouseDown={handleMouseDown}
            onMouseMove={handleMouseMove}
            onMouseUp={handleMouseUp}
          >
            {/* 视口变换容器 */}
            <div
              className="origin-top-left transition-transform duration-200 ease-out"
              style={{
                transform: `translate(${viewport.translateX}px, ${viewport.translateY}px) scale(${viewport.scale})`,
                transformOrigin: '0 0',
                width: canvasSize.width,
                height: canvasSize.height,
              }}
            >
              {/* 画布容器 - 保持固定逻辑尺寸 */}
              <div
                className="relative bg-white shadow-lg border"
                style={{
                  width: '100%',
                  height: '100%',
                }}
              >
                <X6Canvas
                  elements={elements}
                  edges={edges}
                  scale={1} // 始终传递1，保持逻辑坐标系不变
                  canvasSize={canvasSize}
                  viewport={viewport}
                  onSelectElement={setSelectedElement}
                  onUpdateElement={handleUpdateElement}
                  onAddElement={handleAddNode}
                  onRemoveElement={handleRemoveNode}
                  onAddEdge={handleAddEdge}
                  onRemoveEdge={handleRemoveEdge}
                  gridOptions={canvasConfig.grid}
                  backgroundOptions={canvasConfig.background}
                />
              </div>
            </div>

            {/* 视口控制组件 */}
            <ViewportControls
              viewport={viewport}
              onZoomIn={zoomIn}
              onZoomOut={zoomOut}
              onReset={resetViewport}
              onFitToCanvas={handleFitToCanvas}
              canZoomIn={canZoomIn}
              canZoomOut={canZoomOut}
              position="top-right"
            />
          </div>
        </div>

        {/* 右侧属性面板 */}
        <div
          className={`flex flex-col h-full border-l border-gray-200 bg-white transition-all duration-300 ease-in-out shadow-md z-10 ${
            isPropertyPanelCollapsed ? 'w-14' : 'w-80'
          }`}
        >
          <div
            className={`flex items-center p-2 border-b cursor-pointer bg-gray-50 ${
              isPropertyPanelCollapsed ? 'justify-center' : 'justify-start'
            }`}
            onClick={togglePropertyPanel}
          >
            <span aria-label="折叠/展开属性面板">
              {isPropertyPanelCollapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
            </span>
            {!isPropertyPanelCollapsed && <span className="text-sm font-bold ml-2">属性面板</span>}
          </div>
          {!isPropertyPanelCollapsed && (
            <div className="flex-1 overflow-y-auto">
              <PropertyPanel
                selectedElement={selectedElement}
                onUpdateElement={handleUpdateElement}
                onRemoveElement={handleGenericRemove}
                onDuplicateElement={handleDuplicateElement}
                canvasConfig={canvasConfig}
                onCanvasConfigChange={handleCanvasConfigChange}
              />
            </div>
          )}
        </div>
      </div>
    </div>
  );
};

export default GraphEdit;
